//https://www.cnblogs.com/idreamo/p/9249367.html
//https://www.cnblogs.com/en-heng/p/49929
import * as bfun from '../../core/fbyte.js';
/**
 * 邹工的lz77 算法 37798955@qq.com
 * @param {Object} winsize
 */

const Lz77 = function(winsize) {
	winsize = winsize || 54; //窗口缓存	
	winsize = winsize > 255 ? 255 : winsize; //限制宽度
	let self = this;
	/**
	 * 双窗口比较,开窗大小 =winsize 
	 * pp:匹配结果信息
	 * @param {Object} bytes2
	 * @param {Object} off
	 * 
	 返回:格式[[0,1,2],3]
		//0 表示本次比配串开始位置,1下标表示匹配前块最长度,
		//2 表示结尾字符, 3 表示下一次匹配开始位置
	 */
	self.匹配 = function(bytes2, off) {
		if (off == null || off == 0)
			return [
				[0, 0, bytes2[0]], 1
			];
		//窗2长度=可查询长度
		let i2len = Math.min(winsize, off);
		//从 bytes2中截取bytes1,w1 是 bytes1的开始位置
		let w1 = Math.max(off - i2len, 0);
		let bytes1 = bytes2.subarray(w1, w1 + i2len);
		//左补齐bytes1长度使之=winsize,补齐长度为w0
		//最长只能匹配255个长度
		let end2 = Math.min(off + winsize, bytes2.length);
		let pp = null,//输出内容
			p = 0, //匹配个数	
			b1s = 0;
		for (; b1s < i2len; b1s++) {
			let b1j = b1s; //下一次匹配时 bytes1的开始位置
			p = 0;
			for (let b2i = off; b2i < end2;) {
				if (bytes1[b1j] == bytes2[b2i]) {
					b2i++;
					p++;
					b1j++;
					if (b1j == i2len) b1j = 0; //循环移动下标		+ w0			
					if (pp == null || pp[0][1] < p) pp = [
						[b1s, p, bytes2[b2i]], b2i + 1
					]; //如果匹配的更远	
				} else {
					break;
				}
			}
		}
		if (pp == null) pp = [
			[0, 0, bytes2[off]], off + 1
		];
		//匹配信息,下次匹配位置
		return pp;
	}
	self.encode = function(bytes) {
		const max = 1 << 30; //对压缩容量限制		
		let list = [],i = 0, ppp=null;
		list.push(bfun.intToByte4(bytes.length));
		for (let j = 0; i < bytes.length && j < max; j++) {
			ppp = self.匹配(bytes, i);
			if (ppp[0][2] != null)
				list.push(ppp[0]);
			//console.log(ppp[0].toString(), ppp[1])
			i = ppp[1];
		} //console.log(i,ppp)
		return new Uint8Array(list.flat());
	};

	self.decode = function(ui8) {
		let len = bfun.byte4ToInt(ui8, 0);
		//console.log(len)
		let ui82 = new Uint8Array(len);
		let b2j = 0; //已经读取到的字符
		let a, b, c;
		for (let i = 4; i < ui8.length; i += 3) {
			a = ui8[i];
			b = ui8[i + 1]; //长度
			c = ui8[i + 2]; //结尾			
			if (b > 0) {
				let b1 = (winsize > b2j) ? ui82.subarray(0, b2j) : ui82.subarray(b2j - winsize, b2j);
				let b2 = bfun.circleSlice(b1, a, b);
				ui82.set(b2, b2j);
				b2j += b2.length;
			}
			//console.log(a, b, c,b2j)
			ui82.set([c], b2j);
			b2j++;
		}
		return ui82;
	};
	return self;
}
export default Lz77;
